package com.penghaisoft.microwms.common.filter;

import com.alibaba.fastjson.JSON;
import com.penghaisoft.microwms.common.dto.TransResult;
import com.penghaisoft.microwms.common.util.SessionUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.core.StringRedisTemplate;
import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.regex.Pattern;

/**
 * 鉴权过滤器--过滤所有请求
 * Created by zxcq0 on 2018/2/6.
 */
@Slf4j
@Configuration
@ConditionalOnExpression("${auth.check:true}")
@WebFilter(urlPatterns = "/*")
public class SessionFilter implements Filter {

    @Value("${auth.expose-url}")
    private String[] exposeRoot;

    @Value("${auth.login-url}")
    private String[] loginUrl;

    @Value("${auth.expire-time}")
    private Long expireTime;


    @Autowired
    private StringRedisTemplate redisTemplate;


    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
        log.info("=============过滤器初始化==============");
    }

    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        HttpServletRequest request = (HttpServletRequest) servletRequest;
        HttpServletResponse response = (HttpServletResponse) servletResponse;
        String url = request.getRequestURI().substring(request.getContextPath().length());
        log.info("请求url==========="+url);
        String sessionId = getSessionCookie(request);
        log.info("sessionCookie==============="+sessionId);
        if (isExposeUrl(url)){
            log.info("调用外部接口url==========="+url);
            
//            ajax简单请求（表单格式参数） 跨域解决
            response.addHeader("Access-Control-Allow-Origin","*");
            
//            ajax复杂请求（json格式参数） 跨域解决 增加下面三个参数
    		response.setHeader("Access-Control-Allow-Headers", "Content-Type,x-requested-with,Authorization,Access-Control-Allow-Origin");
        	response.setHeader("Access-Control-Allow-Methods", "OPTIONS,GET,POST,DELETE,PUT");
        	response.setHeader("Access-Control-Max-Age", "3600");
        	
            filterChain.doFilter(servletRequest,servletResponse);
        }else if(isLoginUrl(url)){
//          登录url不过滤，直接放行
            log.info("调用登录url===========1"+url);
            
//          ajax简单请求（表单格式参数） 跨域解决
            response.addHeader("Access-Control-Allow-Origin","*");
	          
	//          ajax复杂请求（json格式参数） 跨域解决 增加下面三个参数
	  		response.setHeader("Access-Control-Allow-Headers", "Content-Type,x-requested-with,Authorization,Access-Control-Allow-Origin");
	      	response.setHeader("Access-Control-Allow-Methods", "OPTIONS,GET,POST,DELETE,PUT");
	      	response.setHeader("Access-Control-Max-Age", "3600");
	      	
            filterChain.doFilter(servletRequest,servletResponse);
        }else{
//            业务url
//            要判断是否登陆
            if (!isLogin(request)){
                log.info("当前请求用户未登录，url==========="+url);
                writeError(response,"-1","请登录！");
            }else {
                log.info("当前用户请求通过，重新加载失效时间，url==========="+url);
                if (expireTime == null){
                    expireTime = 3000L;
                }
                SessionUtil.setSessionValueExpireSec(redisTemplate,SessionUtil.SESSION_USER_INFO + sessionId,expireTime);
                SessionUtil.setSessionValueExpireSec(redisTemplate,SessionUtil.SESSION_FACTORY_LIST + sessionId,expireTime);
                SessionUtil.setSessionValueExpireSec(redisTemplate,SessionUtil.SESSION_CURRENT_FACTORY + sessionId,expireTime);
                filterChain.doFilter(servletRequest,servletResponse);
            }
        }
    }

    @Override
    public void destroy() {
        log.info("SessionFilter---------destroy");
    }

    /**
     * 是不是要暴露的url
     * @param url
     * @return
     */
    private boolean isExposeUrl(String url) {
        boolean flag = false;
        for (String expose:exposeRoot ) {
            String pattern = "^/"+ expose +"/.*";
            flag = Pattern.matches(pattern, url);
            if (flag){
                return flag;
            }
        }
        return flag;
    }

    /**
     * 是否登录url
     * @param url
     * @return
     */
    private boolean isLoginUrl(String url) {
        for (String tmpUrl: loginUrl) {
            if (url.equals(tmpUrl)){
                return true;
            }
        }
        return false;
    }

    private String getSessionCookie(HttpServletRequest request){
        String sessionId = "";
        Cookie[] cks = request.getCookies();
        if (cks!=null){
            for (Cookie ck:	cks) {
                if (ck.getName().equals(SessionUtil.SESSION_COOKIE)){
                    sessionId = ck.getValue();
                }
            }
        }
        return sessionId;
    }

    /**
     * 是否登录
     * @param request
     * @return
     */
    private boolean isLogin(HttpServletRequest request) {
        String sessionId = getSessionCookie(request);
        log.info("当前登录人sessionCookie = " + sessionId);
        boolean flag = SessionUtil.existSessionValue(redisTemplate,SessionUtil.SESSION_USER_INFO+sessionId);
        return flag;
    }

    /**
     * 发送错误信息
     * @param response
     * @param code
     * @param errorMsg
     */
    private void writeError(ServletResponse response, String code, String errorMsg) {
        response.setContentType("application/json");
        response.setCharacterEncoding("UTF-8");
        final TransResult result = new TransResult();
        result.setCode(code);
        result.setMsg(errorMsg);
        try {
            response.getWriter().write(JSON.toJSONString((Object)result));
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

}
